package com.ziytek.web.citizen.service;

import com.google.gson.Gson;
import com.ziytek.web.citizen.configuration.RefreshSqliteConfiguration;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.constant.TableConstant;
import com.ziytek.web.citizen.mapper.BoardConfigMapper;
import com.ziytek.web.citizen.mapper.HistoryTableMapper;
import com.ziytek.web.citizen.mapper.TableMapper;
import com.ziytek.web.citizen.model.bean.BatteriesDetails;
import com.ziytek.web.citizen.model.req.BatteryDetailsHistoryQueryReq;
import com.ziytek.web.citizen.model.rsp.BatteryDetailsRsp;
import com.ziytek.web.citizen.model.vo.RealTimeVo;
import com.ziytek.web.citizen.util.DateTimeUtils;
import com.ziytek.web.citizen.util.NumberToUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

/**
 * 电池曲线历史户数查询服务类
 *
 * @author fenghx
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
public class BatteryDetailsHistoryService {

    private final Gson gson;
    private final TableMapper tableMapper;
    private final BoardConfigMapper boardConfigMapper;
    private final HistoryTableMapper historyTableMapper;
    private final CompressionService compressionService;
    private final RefreshSqliteConfiguration refreshSqliteConfiguration;

    public BatteryDetailsRsp historyDetail(BatteryDetailsHistoryQueryReq request) {

        // 当天日期的
        if (StringUtils.isNotBlank(request.getBatchNo()) && DateTimeUtils.isToday(request.getBatchNo())) {
            return dayDetails(request);
        }

        // 非当天日期的,需要寻找DB文件,连接数据库文件,然后再查询数据
        return historyDetails(request);
    }

    private BatteryDetailsRsp dayDetails(BatteryDetailsHistoryQueryReq request) {
        var response = new BatteryDetailsRsp();
        response.success();
        response.setDataCount(NumConstant.INT_ZERO);
        response.setPageNumCount(NumConstant.INT_ZERO);

        var door = request.getDoor();
        var lineNo = request.getLineNo();
        var limit = request.getPageSize();
        var batchNo = request.getBatchNo().replaceAll("-", "")
                .replaceAll(":", "").replaceAll(" ", "");
        var channelNo = request.getChannelNo();
        if (StringUtils.isEmpty(request.getCabinetNo())) {
            request.setCabinetNo("0");
        }
        var cabinetNo = Integer.parseInt(request.getCabinetNo());

        if (StringUtils.isEmpty(door) || lineNo == null || channelNo == null) {
            return response;
        }

        var boardConfig = boardConfigMapper.queryByDoorAndChannelNo(door, lineNo, channelNo);
        if (boardConfig == null) {
            log.error("查询电芯[{}]-[{}]-[{}]的阶段统计数据失败,原因:电芯不存在", door, lineNo, channelNo);
            //response.setRetCode("20001");
            //response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        var tableName = TableConstant.TABLE_REAL_TIME + boardConfig.getAddress();
        var count = tableMapper.queryRealTimeCountByBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo);
        if (count <= NumConstant.INT_ZERO) {
            return response;
        }

        var vdo = tableMapper.queryRealTimeByBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo);
        //log.info("查询电芯[{}]-[{}]的阶段统计数据,总数[{}]-返回[{}]", boardConfig.getAddress(), boardConfig.getChannelNo(), count, vdo.size());

        if (CollectionUtils.isEmpty(vdo)) {
            response.setRetCode("20002");
            response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        List<BatteriesDetails> list = new ArrayList<>();
        response.setDataCount(count);
        var pageCount = (int) Math.ceil((double) count / limit);
        response.setPageNumCount(pageCount);
        for (var r : vdo) {
            byte[] data;
            try {
                data = compressionService.decompress(r.getData());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
            if (v == null) {
                continue;
            }

            var o = new BatteriesDetails();
            o.setType(v.getCty());
            o.setC((float) v.getC());
            o.setV((float) v.getV());
            o.setAt(r.getTime());
            o.setCt(timestampToString(r.getCreateTime()));
            o.setCap(NumberToUtils.doubleToFloat2Decimal(v.getCpa(), NumConstant.INT_TWO));
            list.add(o);
        }

        response.setData(list);
        response.setRetCode(ServerConstant.SUCCESS);
        response.setRetMsg(ServerConstant.SUCCESS_MSG);

        return response;
    }

    private BatteryDetailsRsp historyDetails(BatteryDetailsHistoryQueryReq request) {
        var response = new BatteryDetailsRsp();
        response.success();
        response.setDataCount(NumConstant.INT_ZERO);
        response.setPageNumCount(NumConstant.INT_ZERO);

        var door = request.getDoor();
        var lineNo = request.getLineNo();
        var limit = request.getPageSize();
        var batchNo = request.getBatchNo().replaceAll("-", "")
                .replaceAll(":", "").replaceAll(" ", "");
        var channelNo = request.getChannelNo();
        if (StringUtils.isEmpty(request.getCabinetNo())) {
            request.setCabinetNo("0");
        }
        var cabinetNo = Integer.parseInt(request.getCabinetNo());

        if (StringUtils.isEmpty(door) || lineNo == null || channelNo == null) {
            return response;
        }

        var boardConfig = boardConfigMapper.queryByDoorAndChannelNo(door, lineNo, channelNo);
        if (boardConfig == null) {
            log.error("查询电芯[{}]-[{}]-[{}]的阶段统计数据失败,原因:电芯不存在", door, lineNo, channelNo);
            //response.setRetCode("20001");
            //response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        // 先加载数据库，在切换数据库DB文件
        var dbName = "Data_" + batchNo.substring(NumConstant.INT_TWO, NumConstant.INT_EIGHT);
        log.info("切换历史数据库文件:{}", dbName);
        refreshSqliteConfiguration.updateYmlData("historyDbName", dbName);

        var tableName = TableConstant.TABLE_REAL_TIME + boardConfig.getAddress();
        var count = historyTableMapper.queryRealTimeCountByBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo);
        if (count <= NumConstant.INT_ZERO) {
            return response;
        }

        var vdo = historyTableMapper.queryRealTimeByBatchNo(tableName, cabinetNo, boardConfig.getAddress(), channelNo, batchNo);
        //log.info("查询电芯[{}]-[{}]的阶段统计数据,总数[{}]-返回[{}]", boardConfig.getAddress(), boardConfig.getChannelNo(), count, vdo.size());

        if (CollectionUtils.isEmpty(vdo)) {
            response.setRetCode("20002");
            response.setRetMsg(ServerConstant.ERROR_MSG);
            return response;
        }

        List<BatteriesDetails> list = new ArrayList<>();
        response.setDataCount(count);
        var pageCount = (int) Math.ceil((double) count / limit);
        response.setPageNumCount(pageCount);
        for (var r : vdo) {
            byte[] data;
            try {
                data = compressionService.decompress(r.getData());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            var v = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
            if (v == null) {
                continue;
            }

            var o = new BatteriesDetails();
            o.setType(v.getCty());
            o.setC((float) v.getC());
            o.setV((float) v.getV());
            o.setAt(r.getTime());
            o.setCt(timestampToString(r.getCreateTime()));
            o.setCap(NumberToUtils.doubleToFloat2Decimal(v.getCpa(), NumConstant.INT_TWO));
            list.add(o);
        }

        response.setData(list);
        response.setRetCode(ServerConstant.SUCCESS);
        response.setRetMsg(ServerConstant.SUCCESS_MSG);

        return response;
    }

    private String timestampToString(long timestamp) {
        var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        return sdf.format(new Date(timestamp));
    }

}
